﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MvvmFoundation.Wpf;
using Unscrambler.Data;
using System.Windows.Input;
using System.Configuration;
using System.Windows.Threading;
using Unscrambler.Settings;
using Unscrambler.Extensions;

namespace Unscrambler.ViewModels
{
    public class GameboardViewModel : ObservableObject, IGameboardViewModel
    {
        
        private string _currentWord = string.Empty;
        private int _numberOfWords = 0;
        private int _numberOfCorrectWords = 0;
        private int _wordsPerRound = 0;
        private bool _isGameOver = false;
        private int _elapsedSeconds = 0;
        private DispatcherTimer _timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(1000) };
        private string _hintWord = string.Empty;
        private bool _isCurrentWordCorrect = false;
        private bool _isGameStarted = false;
        
        public event EventHandler<EventArgs> GameEnded;

        public IRandomWordChooser RandomWordChooser
        {
            get;
            set;
        }

        public string CurrentWord
        {
            get { return _currentWord; }
            set
            {
                if (value.Equals(_currentWord))
                    return;

                _currentWord = value;
                base.RaisePropertyChanged("CurrentWord");
            }
        }

        public bool IsGameOver
        {
            get { return _isGameOver; }
            set
            {
                if (value.Equals(_isGameOver))
                    return;

                _isGameOver = value;
                base.RaisePropertyChanged("IsGameOver");
            }
        }

        public int ElapsedSeconds
        {
            get { return _elapsedSeconds; }
            set
            {
                if (value.Equals(_elapsedSeconds))
                    return;

                _elapsedSeconds = value;
                base.RaisePropertyChanged("ElapsedSeconds");
                base.RaisePropertyChanged("ElapsedTime");
            }
        }

        public string ElapsedTime
        {
            get { return _elapsedSeconds.FormatSecondsAsTime(); }
        }

        

        public int NumberOfCorrectWords
        {
            get { return _numberOfCorrectWords; }
            set
            {
                if (value.Equals(_numberOfCorrectWords))
                    return;

                _numberOfCorrectWords = value;
                base.RaisePropertyChanged("NumberOfCorrectWords");
            }

        }

        public string HintWord
        {
            get { return _hintWord; }
            set
            {
                if (value.Equals(_hintWord))
                    return;

                _hintWord = value;
                base.RaisePropertyChanged("HintWord");
            }

        }

        public int NumberOfWords
        {
            get { return _numberOfWords; }
            set
            {
                if (value.Equals(_numberOfWords))
                    return;

                _numberOfWords = value;
                base.RaisePropertyChanged("NumberOfWords");
            }
            
        }

        public bool IsCurrentWordCorrect
        {
            get { return _isCurrentWordCorrect; }
            set
            {
                if (value.Equals(_isCurrentWordCorrect))
                    return;

                _isCurrentWordCorrect = value;
                base.RaisePropertyChanged("IsCurrentWordCorrect");
            }
        }

        
        
        public IGameSettings GameSettings
        {
            get;
            set;
        }

        public ICommand NewWordCommand
        {
            get { return new RelayCommand(GetNewWord); }
        }

        public ICommand SkipWordCommand
        {
            get { return new RelayCommand(SkipCurrentWord); }
        }

        public ICommand StartGameCommand
        {
            get { return new RelayCommand(StartNewGame); }
        }

        public ICommand GetHintCommand
        {
            get { return new RelayCommand(GetNextHint, CanGetHint); }
        }

        public GameboardViewModel()
        {
            _timer.Tick += this.HandleTimerTick;
            
         }

        private void GetNewWord()
        {
            EnsureGameIsStarted();
                        
            NextWordOrEndGame();
            if(NumberOfWords > 1)
                NumberOfCorrectWords += 1;
        }

        private void EnsureGameIsStarted()
        {
            if (!_isGameStarted)
            {
                throw new InvalidOperationException("cannot perform this operation without starting game.");
            }
        }

        private void SkipCurrentWord()
        {
            EnsureGameIsStarted();
            NextWordOrEndGame();
        }

        private void NextWordOrEndGame()
        {
            IsCurrentWordCorrect = false;
            if (NumberOfWords < _wordsPerRound)
            {
                HintWord = string.Empty;
                CurrentWord = RandomWordChooser.GetRandomWord();
                NumberOfWords++;

            }
            else
            {
                IsGameOver = true;
                _isGameStarted = false;
                _timer.IsEnabled = false;
                _timer.Stop();
                OnGameEnded(EventArgs.Empty);
            }
        }

        

        void HandleTimerTick(object sender, EventArgs e)
        {
            if (!_timer.IsEnabled)
                return;
            this.ElapsedSeconds++;
        }

        protected virtual void OnGameEnded(EventArgs e)
        {
            if(GameEnded != null)
                GameEnded(this, e);
        }

        private void StartNewGame()
        {
            EnsureDependenciesHaveBeenInjected();
            
            NumberOfWords = 0;
            NumberOfCorrectWords = 0;
            IsGameOver = false;
            _wordsPerRound = GameSettings.WordsPerRound;
            
            _timer.IsEnabled = true;
            _timer.Start();
            this.ElapsedSeconds = 0;
            _isGameStarted = true;

            GetNewWord();
        }

        private void EnsureDependenciesHaveBeenInjected()
        {
            if (GameSettings == null)
            {
                throw new InvalidOperationException("Game Settings must be set in order to start a game");
            }

            if (RandomWordChooser == null)
            {
                throw new InvalidOperationException("RandomWordChooser must be set in order to start a game");
            }
        }

        private void GetNextHint()
        {
            EnsureGameIsStarted();
            StringBuilder sb = new StringBuilder();
            sb.Append(this.CurrentWord.Substring(0, this.HintWord.Length + 1));
            //assess time penalty for each hint
            this.ElapsedSeconds += GameSettings.SecondsPenaltyPerHint;
            HintWord = sb.ToString();
        }

        private bool CanGetHint()
        {
            return !(HintWord == CurrentWord)  && !(IsGameOver) && !(IsCurrentWordCorrect);
        }

    }
}
